#!/bin/bash
# shellcheck source=meta-facebook/recipes-fb/obmc_functions/files/fb-common-functions
source /usr/libexec/fb-common-functions

GPIO_HIGH=1
GPIO_LOW=0

wait_gpio_value()
{
    local net_name=$1
    local max_retries=$3
    local delay_secs=$4
    local expd_val=$2

    local gpio_val=0
    local trycnt=1

    until [[ $gpio_val -gt 0 || $trycnt -gt $max_retries ]]
    do
        gpio_val=$(get_gpio "$net_name")
        rc=$?
        if [[ $rc -ne 0 ]]; then
            err_msg="Unable to read $net_name"
            echo "$err_msg"
            return 1
        fi
        if [[ $gpio_val -eq $expd_val ]]; then
            return 0
        fi
        sleep "$delay_secs"
        ((trycnt++))
    done

    err_msg="wait_gpio_value failed, gpio_val=$gpio_val,  exp_val=$expd_val"
    echo "$err_msg"
    return 1
}

bind_i2c_muxes()
{
    # Module 0 I2C Mux
    # i2c24 - i2c27
    bind_i2c_device pca954x 0-0071
    # i2c28 - i2c31
    bind_i2c_device pca954x 0-0072
    # i2c32 - i2c35
    bind_i2c_device pca954x 0-0073

    # Module 1 I2C Mux
    # i2c36 - i2c39
    bind_i2c_device pca954x 0-0075
    # i2c40 - i2c43
    bind_i2c_device pca954x 0-0076
    # i2c44 - i2c47
    bind_i2c_device pca954x 0-0077

    # E1S 0 Board I2C Mux, i2c48 - i2c51
    bind_i2c_device pca954x 25-0074
    # E1S 1 Board I2C Mux, i2c52 - i2c55
    bind_i2c_device pca954x 37-0074

}

bind_module_gpio_expanders()
{
    # Module 0 IOEXP
    bind_i2c_device pca953x 2-0020 3
    # Module 1 IOEXP
    bind_i2c_device pca953x 2-0021 3
}

bind_gpio_expanders()
{
    # BMC IOEXP
    bind_i2c_device pca953x 6-0021
    # HMC IOEXP
    bind_i2c_device pca953x 2-0027
    # HMC IOEXP
    bind_i2c_device pca953x 2-0074
    # IO Mezz 0 IOEXP
    bind_i2c_device pca953x 29-0020
    # IO Mezz 1 IOEXP
    bind_i2c_device pca953x 41-0021
}

bind_fru_eeproms()
{
    # HMC FRU
    bind_i2c_device at24 13-0057
    # Module 0 FRU
    bind_i2c_device at24 13-0050
    # Module 1 FRU
    bind_i2c_device at24 12-0050
    # CBC 0 and 1 FRU
    bind_i2c_device at24 13-0054
    bind_i2c_device at24 13-0055
    # CBC 2 and 3 FRU
    bind_i2c_device at24 12-0054
    bind_i2c_device at24 12-0055
    # Module 0 Aux
    bind_i2c_device at24 2-0050
    # Module 1 Aux
    bind_i2c_device at24 2-0051
    # IO Mezz 0 FRU
    bind_i2c_device at24 29-0050
    # IO Mezz 1 FRU
    bind_i2c_device at24 41-0050
    # E1S 0 Board FRU
    bind_i2c_device at24 25-0056
    # E1S 1 Board FRU
    bind_i2c_device at24 37-0056
    # CX7 0 FRU
    bind_i2c_device at24 10-0050
    # CX7 1 FRU
    bind_i2c_device at24 15-0052
    # OSFP FRU
    bind_i2c_device at24 29-0052
}

bind_hsc_sensors()
{
    bind_i2c_device lm25066 1-0012
    bind_i2c_device lm25066 1-0014
    bind_i2c_device lm75 1-004e
}

bind_pdb_sensors()
{
   bind_i2c_device isl68137 1-0060
   bind_i2c_device isl68137 1-0061
}

bind_interposer_sensors()
{
    bind_i2c_device ina238 16-0041
    bind_i2c_device ina238 16-0042
    bind_i2c_device ina238 16-0044

    bind_i2c_device ina238 23-0042
    bind_i2c_device ina238 23-0044
}

reset_host_usb()
{
    set_gpio "USB2_HUB_RST_L-O" "$GPIO_LOW"
    set_gpio "SEC_USB2_HUB_RST_L" "$GPIO_LOW"
    sleep 1
    set_gpio "USB2_HUB_RST_L-O" "$GPIO_HIGH"
    set_gpio "SEC_USB2_HUB_RST_L" "$GPIO_HIGH"
}

reset_i2c_mux()
{
    set_gpio "I2C_BUS_MUX_RESET_L-O" "$GPIO_LOW"
    set_gpio "SEC_I2C_BUS_MUX_RESET_L" "$GPIO_LOW"
    sleep 1
    set_gpio "I2C_BUS_MUX_RESET_L-O" "$GPIO_HIGH"
    set_gpio "SEC_I2C_BUS_MUX_RESET_L" "$GPIO_HIGH"
}

rebind_hmc_usb_network()
{
    echo 1e6a1000.usb > /sys/bus/platform/drivers/ehci-platform/unbind
    echo 1e6a1000.usb > /sys/bus/platform/drivers/ehci-platform/bind
}

is_stby_good()
{
    local gpio_val

    if ! gpio_val=$(get_gpio "STBY_POWER_PG_3V3"); then
        return 1
    fi

    if [[ $gpio_val -eq 0 ]]; then
        return 1
    fi

    return 0
}

set_bmc_ready()
{
    local bmc_ready="/sys/class/leds/bmc_ready_noled/brightness"
    local bmc_ready_cpld="/sys/class/leds/bmc_ready_cpld_noled/brightness"

    echo 1 > ${bmc_ready}
    echo 1 > ${bmc_ready_cpld}
    return 0
}

is_hmc_reachable()
{
    local max_retry_count="$1"
    for retry in $(seq 1 "$max_retry_count")
    do
        if ping -c 1 -W 1 172.31.13.251; then
            echo "HMC is reachable"
            return 0
        fi
        echo "HMC is not reachable, retry count: $retry"
    done
    return 1
}

enable_pdb_vr_setting()
{
    i2cset -f -y 1 0x60 0xEB 0x0796 w
    i2cset -f -y 1 0x61 0xEB 0x0796 w
}

restart_eth()
{
    for i in {1..2}
    do
    echo "Attempt $i to restart eth0 and eth1..."
    /bin/sh -c 'echo "BMC: Executing eth0 down" && /sbin/ip link set eth0 down'
    /bin/sh -c 'echo "BMC: Executing eth1 down" && /sbin/ip link set eth1 down'
    sleep 1
    /bin/sh -c 'echo "BMC: Executing eth0 up" && /sbin/ip link set eth0 up'
    /bin/sh -c 'echo "BMC: Executing eth1 up" && /sbin/ip link set eth1 up'
    sleep 20
    if /sbin/ip a show eth0 | grep -q "inet " && /sbin/ip a show eth1 | grep -q "inet "; then
        echo "eth0 and eth1 are up and both have IPs"
        return 0
    fi
    done
}

if ! is_stby_good; then
    set_gpio "SCM_HPM_STBY_RST_N" "$GPIO_LOW"
fi

set_gpio "SCM_HPM_STBY_EN" "$GPIO_HIGH"
set_gpio "stby_power_en_cpld" "$GPIO_HIGH"
if ! wait_gpio_value "STBY_POWER_PG_3V3" "$GPIO_HIGH" 200 0.1; then
    echo "Error: failed to get STBY_POWER_PG_3V3 as high (1) in 20 sec"
    exit 1
fi
set_gpio "BMC_12V_CTRL" "$GPIO_HIGH"
set_gpio "stby_power_gd_cpld" "$GPIO_HIGH"

# bind module io expanders earily due to i2c mux reset pin needed
bind_module_gpio_expanders

reset_i2c_mux
bind_i2c_muxes
sleep 3 # This is to ensure that all downstream node drivers probe completed
reset_i2c_mux
bind_gpio_expanders

set_gpio "HMC_PGOOD-O" "$GPIO_HIGH"
set_gpio "EROT_FPGA_RST_L-O" "$GPIO_HIGH"
set_gpio "SEC_EROT_FPGA_RST_L" "$GPIO_HIGH"
set_gpio "HMC_EROT_RST_L-O" "$GPIO_HIGH"
set_gpio "SCM_HPM_STBY_RST_N" "$GPIO_HIGH"

if ! wait_gpio_value "HMC_READY-I" "$GPIO_HIGH" 180 1; then
    restart_eth
    echo "Error: failed to get HMC_READY-I as high (1) in 180 sec"
    exit 1
fi

reset_host_usb

if ! is_hmc_reachable 10; then
    rebind_hmc_usb_network
fi

if ! wait_gpio_value "FPGA_READY_BMC-I" "$GPIO_HIGH" 180 1; then
    restart_eth
    echo "Error: failed to get FPGA_READY_BMC-I as high (1) in 180 sec"
    exit 1
fi

if ! wait_gpio_value "SEC_FPGA_READY_BMC" "$GPIO_HIGH" 180 1; then
    restart_eth
    echo "Error: failed to get SEC_FPGA_READY_BMC as high (1) in 180 sec"
fi

bind_fru_eeproms

# rebind Sensors
bind_hsc_sensors
bind_pdb_sensors
bind_interposer_sensors

enable_pdb_vr_setting

set_bmc_ready

# restart eth0 and eth1 interfaces for get the correct MAC address
if ! restart_eth ; then
    echo "Failed to bring up IPv6 Scope:Global after 2 attempts."
fi

exit 0
